﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace pshcli
{

    public class Dwarf2
    {

        public GlobalSettings _gsettings;
        public string platform;
        public string parallel;
        public string size;
        public string internalname;
        public string customstr;

        public string dwarfname;
        public string bin;
        public string args;
        public string workdir;

        public string inputfile;
        public string resultfile;
        public string profilefile;

        public bool xperftrace;
        public string xperftracefile;

        public string scheduler;
        public bool mpitrace;
        public string mpitracefile;
        public string mpitracedir;
        //public string mpitracestr;
        public string lmpitracedir;

        public string otff = "";
        public string clogf = "";


        public string inputfileswitch = "/inputfile:";
        public string resultfileswitch = "/resultfile:";
        public string profilefileswitch = "/profilefile:";

        public string mpiexecstr;

        public string jobstr;
        public int numthreads;
        public int numprocs;

        public bool success;
        public string errormsg;
        public string resultdir;
        public string profiledir;

        public string log_process_execution_string;



        public Dwarf2
            (
            string name,
            string platform,
            string parallel,
            string size,

            //string dwarfname,
            string bin,
            string args,
            string workdir,

            string inputfile,
            string resultfile,
            string profilefile,

            bool mpitrace,
            bool xperftrace,

            string mpiexecstr,
            string scheduler,
            string jobstr,
            int numthreads,
            int numprocs
            )
        {
            this.internalname = name;
            this.dwarfname = "Dwarf." + internalname.ToString();

            this.platform = platform;
            this.parallel = parallel;
            this.size = size;

            this.bin = bin;
            this.args = args;
            this.workdir = workdir;

            this.inputfile = inputfile;
            this.resultfile = resultfile;
            this.profilefile = profilefile;

            this.mpitrace = mpitrace;
            this.xperftrace = xperftrace;

            if (xperftrace)
                this.xperftracefile = ConstructXperfEtlFileName();

            if (mpitrace)
                this.mpitracefile = ConstructMpiEtlFileName();

            this.mpiexecstr = mpiexecstr;
            this.scheduler = scheduler;
            this.jobstr = jobstr;
            this.numthreads = numthreads;
            this.numprocs = numprocs;

            success = false;
            log_process_execution_string = "";
        }


        //Replace sufix for tracing output
        public string ConstructXperfEtlFileName()
        {
            string str = this.profilefile.Replace(".txt", ".xperf.etl");
            //HelperMethods.CheckFile(str);
            return str;
        }

        public string ConstructMpiEtlFileName()
        {
            string str = this.profilefile.Replace(".txt", ".mpi.etl");
            //HelperMethods.CheckFile(str);
            return str;
        }

        public string ConstructExecCommandForCluster()
        {
            string cmd = ""; //"mpiexec ";

            //if (this.mpitrace)
            //    if (!String.IsNullOrEmpty(this.mpitracefile))
            //    {
            //        cmd += " -trace " + mpitracestr + " -tracefile " + this.mpitracefile;
            //    }
            //    else
            //    {
            //        cmd += " -trace ";
            //    }

            //cmd += "\"" + _gsettings.nodelocaltargetdir + this.GetExecName() + ".exe" + "\" ";
            cmd += this.GetExecName() + ".exe" + " ";

            //add inputfile
            cmd += inputfileswitch + this.inputfile + " ";

            //add result file
            cmd += resultfileswitch + this.resultfile + " ";

            //add profile file
            cmd += profilefileswitch + this.profilefile + " ";

            //add default args
            cmd += args + " ";

            return cmd;
        }

        public string ConstructExecCommand()
        {
            string cmd = "";

            //add mpiexec
            if (parallel.Contains("mpi") || parallel.Contains("mpinet") || parallel.Contains("hybrid"))
            {
                cmd += ConstructMpiexecStr() + " ";
            }

            //add inputfile
            cmd += inputfileswitch + "\"" + this.inputfile + "\" ";

            //add result file
            cmd += resultfileswitch + "\"" + this.resultfile + "\" ";

            //add profile file
            cmd += profilefileswitch + "\"" + this.profilefile + "\" ";

            //add default args
            cmd += args + " ";

            return cmd;
        }

        public string ConstructMpiexecStr()
        {
            //string tmp = "mpiexec " + mpiexecstr;
            string tmp = mpiexecstr;

            if (this.mpitrace)
            {
                string profile = "(All)";
                if (!String.IsNullOrEmpty(DwarfBench.gsettings.mpicounterselect))
                    profile = DwarfBench.gsettings.mpicounterselect;
                else
                    profile = "(All)";

                if (!String.IsNullOrEmpty(this.mpitracefile))
                {
                    tmp += " -trace " + profile + " -tracefile " + "\"" + this.mpitracefile + "\"";
                }
                else
                {
                    tmp += " -trace " + profile;
                }
            }
            tmp += " \"" + bin + "\" ";
            return tmp;

        }

        public string GetExecName()
        {
            return "Dwarf." + internalname + "." + platform.ToString() + "." + parallel.ToString();
        }

        //Results section
        public Object _size;
        public double time;

        public bool GetResult(ref string errormsg)
        {
            //check output file
            if (HelperMethods.IsFileReadable(profilefile, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                TextReader txtreader = new StreamReader(profilefile);
                this.time = -1;

                while (true)
                {
                    string content = txtreader.ReadLine();
                    if (content == null)
                        break;
                    else if (content.Contains("time"))
                    {
                        try
                        {
                            string[] strarr = content.Split(' ');
                            //                            if (strarr.Length == 0)
                            //                                return false;
                            if (strarr.Length != 0)
                            {
                                foreach (string token in strarr)
                                {
                                    try
                                    {
                                        this.time = Double.Parse(token);
                                    }
                                    catch (Exception) { }
                                }
                            }
                        }
                        catch (Exception) { }
                        return false;
                    }
                }

                errormsg = "file empty or not readable";
                return false;
            }
            else
            {
                DwarfBench.glog.WriteLog("GET_RESULTS", "Error reading file " + profilefile);
                errormsg = "file missing or not readable";
                return false;
            }

        }

        //Consistency checks
        public bool CeckConsistency(Log glog, ref string message)
        {
            glog.WriteLog("CONSISTENCY_CHECK", "Checking " + internalname);

            if (!HelperMethods.IsFileReadable(this.bin, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                glog.WriteLog("CONSISTENCY_CHECK", "   >Cannot read executable " + this.bin);
                message = "missing exe";
                return false;
            }


            if (!HelperMethods.IsFileReadable(this.inputfile, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                glog.WriteLog("CONSISTENCY_CHECK", "   >Cannot read input file " + this.inputfile);
                message = "missing input";
                return false;
            }


            //Check resultfile
            try
            {
                HelperMethods.IsFileReadable(this.resultfile, FileMode.CreateNew, FileAccess.Write, FileShare.None);
                glog.WriteLog("CONSISTENCY_CHECK", "   >Result file exists: " + this.resultfile);
            }
            catch (Exception e)
            {
                if (e.Message.Contains("already exists"))
                {
                    if (!HelperMethods.DeleteFile(resultfile))
                    {
                        glog.WriteLog("CONSISTENCY_CHECK", "Checking " + internalname + ": FAILED.");
                        return false;
                    }
                    else
                        glog.WriteLog("CONSISTENCY_CHECK", "   >Existing profile file deleted.");
                }
                else
                    glog.WriteLog("CONSISTENCY_CHECK", "   >Error deleting result file occured " + e.Message);
            }

            //Check profile file
            try
            {
                HelperMethods.IsFileReadable(this.profilefile, FileMode.CreateNew, FileAccess.Write, FileShare.None);
                glog.WriteLog("CONSISTENCY_CHECK", "   >Result file exists: " + this.profilefile);
            }
            catch (Exception e)
            {
                if (e.Message.Contains("already exists"))
                {
                    if (!HelperMethods.DeleteFile(resultfile))
                    {
                        glog.WriteLog("CONSISTENCY_CHECK", "Checking " + internalname + ": FAILED.");
                        return false;
                    }
                    else
                        glog.WriteLog("CONSISTENCY_CHECK", "   >Existing result file deleted.");
                }
                else
                    glog.WriteLog("CONSISTENCY_CHECK", "   >Error deleting profile file occured " + e.Message);
            }

            glog.WriteLog("CONSISTENCY_CHECK", "Checking " + internalname + ": OK.");
            return true;
        }
    }
}
